﻿import { _decorator, Component, Node, Asset, loader, instantiate, Prefab, resources, assetManager, sys, SpriteFrame } from 'cc';
import { ResourcesObjBase } from '../base/ResourcesObjBase';
import { DestroyCB } from './DestroyCB';
import { SysMgr } from './SysMgr';
import { TimeSys } from '../sys/TimeSys';
import { Functor } from './Functor';
const { ccclass, property } = _decorator;



@ccclass('ResourceLoader')
export class ResourceLoader {
    static pathAssetMap = new Map;//路径对应资源
    static objPathMap = new Map;//实例化资源对应路径
    static assetRefMap = new Map;//路径对应引用计数

    static clear() {
        ResourceLoader.pathAssetMap.clear();
        ResourceLoader.objPathMap.clear();
        ResourceLoader.assetRefMap.clear();

    }

    public static async loadAsset<T extends Asset>(path): Promise<T> {

        return new Promise((resolve, reject) => {
            let asset = ResourceLoader.pathAssetMap.get(path);
            if (asset != undefined) {//asset已经加载了
                ResourceLoader.assetRefMap.set(path, ResourceLoader.assetRefMap.get(path) + 1);
                resolve(asset);
            }
            loader.loadRes<T>(path, function (err, newAsset) {
                //newAsset["_asset_path"] = path;
                //newAsset.addRef();
                if (newAsset == null) {
                    resolve(newAsset);
                } else {
                    newAsset.addRef();//不加的话 有时候切换场景会自动被释放
                    ResourceLoader.pathAssetMap.set(path, newAsset);
                    ResourceLoader.assetRefMap.set(path, 1);
                    resolve(newAsset);
                }
                    

            });
        })

    }

    public static releaseAsses(path: string) {
        if (!ResourceLoader.assetRefMap.has(path))
            return;
        let refCount = ResourceLoader.assetRefMap.get(path);
        refCount -= 1;
        ResourceLoader.assetRefMap.set(path, refCount);
        if (refCount == 0) {
            let asset: Asset = ResourceLoader.pathAssetMap.get(path);
            asset.decRef();
            ResourceLoader.pathAssetMap.delete(path);
            ResourceLoader.assetRefMap.delete(path);
            loader.release(asset);
        }
    }

    public static async insNode(path): Promise<Node> {
        let newAsst = await ResourceLoader.loadAsset<Prefab>(path);
        let newObj = instantiate(newAsst);
        ResourceLoader.objPathMap.set(newObj, path);
        let com = newObj.addComponent(ResourcesObjBase);
        DestroyCB.addCb(com, this, "_destroyNode")
        return newObj;

    }

    public static _destroyNode(watchDestroyObj: ResourcesObjBase) {
        SysMgr.getSys(TimeSys).addTimer(this, Functor.getFunc(this, "_delay_destroyNode"), 0.01, false);
    }

    static _delay_destroyNode(watchDestroyObj: ResourcesObjBase) {
        let obj = watchDestroyObj.node;
        if (!ResourceLoader.objPathMap.has(obj)) {
            return;
        }
        let path = ResourceLoader.objPathMap.get(obj);
        ResourceLoader.objPathMap.delete(obj);
        ResourceLoader.releaseAsses(path);
    }

}

